#pragma once

#include <iostream>
#include <string>
#include <vector>
#include <sstream>
#include <unordered_map>
#include "Log.hpp"
#include "Common.hpp"

const std::string Sep = "\r\n";
const std::string LineSep = " ";
const std::string HeaderLineSep = ": ";
const std::string http_version = "HTTP/1.0";
const std::string defaulthomepage = "wwwroot";
const std::string page404 = "wwwroot/404.html";
const std::string firstpage = "index.html";

using namespace LogMoudule;
class HttpRequest
{
private:
    void ParseReqLine(std::string &_req_line, const std::string sep)
    {
        (void)sep;
        std::stringstream ss(_req_line);
        ss >> _method >> _uri >> _version;
    }
    bool ParseHeaderLine(std::string &request_str)
    {
        std::string line;
        while (true)
        {
            bool r = ParseOneLine(request_str, &line, Sep);
            if (r && !line.empty())
            {
                _req_header.push_back(line);
            }
            else if (r && line.empty())
            {
                _blank_line = line;
                break;
            }
            else
            {
                return false;
            }
        }
        return true;
    }
    void ParseHeaderkv()
    {
        std::string key;
        std::string value;
        for (auto &line : _req_header)
        {
            SplitString(line, &key, &value, HeaderLineSep);
            _headerkv.insert(std::make_pair(key, value));
        }
    }

public:
    void Deserialize(std::string &request_str)
    {
        if (ParseOneLine(request_str, &_req_line, Sep))
        {
            ParseReqLine(_req_line, LineSep);
            ParseHeaderLine(request_str);
            _body = request_str;
        }
    }
    std::string GetContent(std::string path)
    {
        std::string content;
        std::ifstream in(path, std::ios::binary);
        if (!in.is_open())
            return std::string();
        in.seekg(0, in.end);
        int filesize = in.tellg();
        in.seekg(0, in.beg);

        content.resize(filesize);
        in.read((char *)content.c_str(), filesize);
        in.close();
        LOG(LogLevel::DEBUG) << "content length: " << content.size();
        return content;
        // std::ifstream in(_uri);
        // if (!in.is_open())
        //     return std::string();

        // std::string content;
        // std::string line;
        // while (getline(in, line))
        // {
        //     content += line;
        // }
        // in.close();
        // return content;
    }
    std::string Uri() { return _uri; }
    void SetUri(std::string uri) { _uri = uri; }
    void Print()
    {
        std::cout << "_method: " << _method << std::endl;
        std::cout << "_uri: " << _uri << std::endl;
        std::cout << "_version: " << _version << std::endl;

        for (auto &kv : _headerkv)
        {
            std::cout << kv.first << " # " << kv.second << std::endl;
        }
        std::cout << "_blank_line: " << _blank_line << std::endl;
        std::cout << "_body: " << _body << std::endl;
    }
    std::string Suffix()
    {
        auto pos=_uri.rfind(".");
        if(pos==std::string::npos) return std::string();
        return _uri.substr(pos);
    }
private:
    std::string _req_line;
    std::vector<std::string> _req_header;
    std::string _blank_line;
    std::string _body;
    std::string _method;
    std::string _uri;
    std::string _version;
    std::unordered_map<std::string, std::string> _headerkv;
};

class HttpResponse
{
public:
    HttpResponse()
        : _version(http_version)
    {
    }
    void build(HttpRequest &req)
    {
        std::string uri = defaulthomepage + req.Uri();
        if (req.Uri() == "/")
        {
            uri += firstpage;
            req.SetUri(uri);
        }
        LOG(LogLevel::DEBUG) << "------客户端在请求: " << req.Uri();
        _content = req.GetContent(uri);
        req.Print();
        if (_content.empty())
        {
            _code = 404;
            _content=req.GetContent(page404);
        }
        else
            _code = 200;
        if (!_content.empty())
            SetHeader("Content-Length", std::to_string(_content.size()));
        SetHeader("Content-Type",Suffix2Desc(uri));
        _codedesc = CodeToDesc(_code);
        _blank_line = Sep;
    }
    void Seserialize(std::string *out)
    {
        for (auto &header : _header_kv)
        {
            _resp_header.push_back(header.first + HeaderLineSep + header.second + Sep);
        }
        _resp_line = _version + LineSep + std::to_string(_code) + LineSep + _codedesc + Sep;
        _body = _content;

        // 序列化
        *out = _resp_line;
        for (auto &line : _resp_header)
        {
            *out += line;
        }
        *out += _blank_line;
        *out += _body;
    }
    void SetHeader(const std::string &k, const std::string &v)
    {
        _header_kv[k] = v;
    }
    ~HttpResponse()
    {
    }

private:
    std::string CodeToDesc(int code)
    {
        switch (code)
        {
        case 200:
            return "OK";
        case 404:
            return "Not Found";
        case 301:
            return "Moved Permanently";
        case 302:
            return "Found";
        default:
            return std::string();
        }
    }
     std::string Suffix2Desc(const std::string &suffix)
    {
        if (suffix == ".html")
            return "text/html";
        else if (suffix == ".jpg")
            return "application/x-jpg";
        else
            return "text/html";
    }
    std::string _version;
    int _code;
    std::string _codedesc;
    std::string _content;
    std::unordered_map<std::string, std::string> _header_kv;

    std::string _resp_line;
    std::vector<std::string> _resp_header;
    std::string _blank_line;
    std::string _body;
};